<template>
  <div>
    <table>
      <thead>
        <tr>
          <th
            v-for="(item, index) in columns"
            :key="index"
            :class="{ active: sortKey === item.field }"
            @click="sortBy(item.field)"
          >
            <span>{{ item.title }}</span>
            <span
              v-if="item.sort"
              class="arrow"
              :class="sortOrders[item.field] > 0 ? 'asc' : 'dsc'"
            ></span>
          </th>
        </tr>
      </thead>

      <tbody>
        <tr v-for="(row, index) in displayRows" :key="index">
          <td v-for="(col, index) in columns" :key="index">
            {{ row[col.field] }}
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
export default {
  props: {
    columns: Array, // 列
    rows: Array, // 行
    filterKey: String, // 过滤的内容
    // 默认排序的字段
    defaultSortKey: {
      type: String,
      default: "",
    },
    // 默认排序的规则 asc 正序 dsc 倒序
    defaultSortOrder: {
      type: String,
      default: "asc",
      validator: (value) => {
        return ["asc", "dsc"].includes(value);
      },
    },
  },

  data() {
    return {
      sortKey: this.defaultSortKey, // 排序字段
      /**
       * 排序的字段集合
       *    基于 columns 生成
       */
      sortOrders: this.columns
        .filter((item) => item.sort)
        .reduce((result, item) => {
          result[item.field] = this.defaultSortOrder === "asc" ? 1 : -1;
          return result;
        }, {}),
    };
  },

  computed: {
    /**
     * 用于页面展示使用的 rows
     *    依赖项目：rows、sortOrders、sortKey
     */
    displayRows() {
      let result = [...this.rows];

      const filterKey = this.filterKey && this.filterKey.toLowerCase();

      if (filterKey) {
        // 过滤
        result = result.filter((row) => {
          // Object.keys(row) ['name', 'age']
          return Object.keys(row).some((key) => {
            return String(row[key]).toLowerCase().includes(filterKey);
          });
        });
      }

      if (this.sortKey) {
        // 获取当前排序字段的规则：1 【正序】 or -1 【倒序】
        const order = this.sortOrders[this.sortKey];

        result = result.sort((a, b) => {
          a = a[this.sortKey];
          b = b[this.sortKey];
          return (a === b ? 0 : a > b ? 1 : -1) * order;
        });
      }

      return result;
    },
  },

  methods: {
    sortBy(field) {
      // 判断，当前 field 是否可以排序
      if (!this.columns.find((item) => item.field === field).sort) return;

      this.sortKey = field;
      this.sortOrders[field] = this.sortOrders[field] * -1;
    },
  },
};
</script>

<style>
table {
  border: 2px solid #42b983;
  border-radius: 3px;
  background-color: #fff;
}

th {
  background-color: #42b983;
  color: rgba(255, 255, 255, 0.66);
  cursor: pointer;
  user-select: none;
}

td {
  background-color: #f9f9f9;
}

th,
td {
  min-width: 120px;
  padding: 10px 20px;
}

th.active {
  color: #fff;
}

th.active .arrow {
  opacity: 1;
}

.arrow {
  display: inline-block;
  vertical-align: middle;
  width: 0;
  height: 0;
  margin-left: 5px;
  opacity: 0.66;
}

.arrow.asc {
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-bottom: 4px solid #fff;
}

.arrow.dsc {
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 4px solid #fff;
}
</style>
